#include <fstream>
#include <cstdarg>

#ifdef MEMLEAKTEST
#include "nvwa/debug_new.h"
#endif

// debugging macros. primarily used to trace the values of
// variables and follow the order of program exectution.
#define DEBUG(expr) { expr; std::cout << #expr << std::endl; }
#define TOKEN(expr) #expr << " = " << expr

// string equality
#define STR_EQUAL(a, b) (std::strcmp((a), (b))==0)

// general purpose constants
int const C_STR_SIZE = 512;

// depends on the precision necessary
typedef long double 			FLT_NUMBER;

// strings (char pointers) are ugly things in C
typedef char* 					C_STR;
typedef const char* const 		CONST_C_STR;

// newline character
CONST_C_STR NEWLINE = "\n";

// fixed-size string trick
template <unsigned int L> struct FIX_STRING { char str[L]; };

// how many moves (plies) do we iterate through the move list
int const ALPHABETA_DEFAULT_DEPTH = 4;

// how often (number of transactions) do we reset the history table memory
int const HIST_TBL_MEMORY = 20;

// alphabeta safety cutoff to prevent deadlocking the machine
unsigned int const ALPHABETA_SAFETY_CUTOFF = 10;

// flags to turn on or off certain features
bool const SEARCH_EXTENSIONS = false;
bool const USE_OPENING_BOOKS = true;

// ERROR REPORTING AND ALGORITHM TRACING:
// reporting should always start with a keyword in all capital letters
// to enhance readibility of error tracing. this keyword should be descriptive,
// such as SUCCESS, FAILURE, BEGAN, COMPLETED, et cetera.

// legal trace values. use constants, not numbers
int const TRACE_LEVEL_OFF = 0;
int const TRACE_LEVEL_FATAL = 1;
int const TRACE_LEVEL_WARN = 2;
int const TRACE_LEVEL_INFO = 3;
int const TRACE_LEVEL_DEBUG = 4;
int const TRACE_LEVEL_ALL = 5;

// trace variables
CONST_C_STR TRACE_LOG_FILENAME = "trace.log";
std::ofstream ERROUT(TRACE_LOG_FILENAME);

// chess log (to track the game)
CONST_C_STR GAME_LOG_FILENAME = "chess.log";
std::ofstream CHESSOUT(GAME_LOG_FILENAME);

// current trace level
int TRACE_LEVEL = TRACE_LEVEL_ALL;

// variadic macros to make life easier
#define trace(level, msg...) 			trace_message(level, msg, (C_STR)0)
#define trace_assert(test, msg...) 		if (test) {} else trace_message(TRACE_LEVEL_FATAL, msg, (C_STR)0)

// trace error messages to the trace log
void trace_message(int level, ...)
{
	// quit early if there is no debugging to be done
	if (level > TRACE_LEVEL) return;
	
	C_STR msg; va_list args;
	va_start(args, level);
	
	// print until we find the null character
	while (msg = va_arg(args, C_STR)) ERROUT << msg;
	ERROUT << std::endl;
	
	// if the level is fatal, we need to fail-quit
	if (level == TRACE_LEVEL_FATAL) std::exit(EXIT_FAILURE);
};

#ifdef NDEBUG
	#undef trace_assert
	#define trace_assert(test, msg...)
	
	#undef trace
	#define trace(level, msg...)
#endif

// constant files
#include "i_board/i_board.const.h"
#include "i_table/i_table.const.h"
#include "i_search/i_search.const.h"
#include "i_data/i_data.const.h"
#include "i_game/i_game.const.h"

// prototype files
#include "i_board/i_board.proto.h"
#include "i_table/i_table.proto.h"
#include "i_search/i_search.proto.h"
#include "i_data/i_data.proto.h"
#include "i_game/i_game.proto.h"

// implementation files
#include "i_board/i_board.h"
#include "i_table/i_table.h"
#include "i_search/i_search.h"
#include "i_data/i_data.h"
#include "i_game/i_game.h"
